﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using RayDen.Library.Core;
using RayDen.Library.Entity.Frames;
using RayDen.Library.Entity.Interface;
using RayDen.RayEngine;
using RayDen.RayEngine.Core.Interface;
using RayDen.RayEngine.Engines.PathTracer;
using RayDen.SmallRT.Components;
using RayDen.SmallRT.Integrators;

namespace RayDen.SmallRT
{
    public class SmallRtConfig : IRenderConfig
    {
        private BaseIntegrator integrator;
        private string imagesPath = GlobalConfiguration.Instance.Get<string>("ImageSaveDirectory");
        private IImageFilm film;
        protected IParameterBag config;

        protected Task renderTask;
        protected CancellationTokenSource token;
        public string SavePath
        {
            get { return imagesPath; }
        }

        public string FrameName { get { return "SPT_"+integrator.GetType().Name; } protected set { } }

        public int Width
        {
            get { return config.Get<int>("ImageWidth"); }
        }
        public int Height
        {
            get { return config.Get<int>("ImageHeight"); }
        }

        public void SaveImage(string fn)
        {
            this.film.SavePNG(fn, this.integrator.GetStats().Split(';').Union(new[] { integrator.GetType().Name }).ToArray());
        }

        public void SaveRawImage(string fn)
        {
            this.film.SaveRaw(fn);
        }

        public void OpenFrame(FrameDescription frameDescription)
        {
            this.config = frameDescription;
            if (GlobalConfiguration.Instance.AdaptiveFilm)
                this.film = new AdaptiveImageFilm(this.Width, this.Height);
            else 
                this.film = new ImageFilm(this.Width, this.Height);
            this.integrator = 
                //new PathTracerIntegrator()
                //new PathTracerDL()
                //new RayTracer()
                new SpectralRayTracer()

                //new SingleRandomWavelengthPathTracerIntegrator()
                //new WavelengthClusterPathTracerIntegrator()
            {
                Scene = new SceneManager() { w = this.Width, h = this.Height },
                film = this.film,
                rnd = new FastRandom()
            };
        }

        private Stopwatch sw;
        public void Start()
        {
            token = new CancellationTokenSource();
            this.integrator.InitPass();
            sw = Stopwatch.StartNew();
            renderTask = Task.Run(() =>
            {
                while (true)
                {
                    this.integrator.RunRenderer(token.Token);
                    if (token.IsCancellationRequested)
                    {
                        break;
                    }
                }
            }, token.Token);
        }

        public void Interrupt()
        {
            sw.Stop();
            this.token.Cancel();
        }

        public void ConsumeJob(IRenderJob job, Action<IRenderJobResult> resultCallback)
        {
            throw new NotImplementedException();
        }

        public string GetStats()
        {
            return string.Format("Elapsed {1}, {0} ", this.integrator.GetStats(),sw.Elapsed);
        }

        public void Dispose()
        {
           

            if (renderTask != null)
            {
                if (!renderTask.IsCompleted)
                {
                    token.Cancel();
                    while (!renderTask.IsCanceled) { }
                }
                renderTask.Dispose();
            }
            if (token != null)
            {
                token.Dispose();
            }
        }

        public void RunCommand(int index)
        {
            throw new NotImplementedException();
        }

        public IImagePlaneComponent GetImagePlane()
        {
            return film;
        }
    }
}
